import json
import os
import socket
import struct
from loguru import logger
from typing import Type

from app.core.conf import ST


class AGV:

    __slots__ = ('socket_pool','ip','port')

    agv = {}

    def __init__(self,ip,port):
        self.ip = ip
        self.port = port
        self.socket_pool = {}
        self.init_socket_pool()


    def ping_agv(self):
        res = os.system('ping 10.13.32.11')
        logger.debug('ping 10.13.32.11 : ')
        print(res)
        if res == 0:
            logger.info('5G连接正常')
            return True 
        else:
            logger.warning('5G断开连接,')
            return False


    def init_socket_pool(self):
        if not self.ping_agv():
            return

        if self.socket_pool: # 如果socket pool,已经初始化,不为空,则返回
            return

        for name,port in self.port.items():
            self.socket_pool[name] = self.connect(port,name)
        


    def send(self,name,req_id, msg_type, msg={}):
        """_summary_

        Args:
            name (_type_): _
                            'status':19204,
                            'control':19205,
                            'nav':19206,
                            'config':19207,
                            'other':19210,
                            'push':19301
            _
            req_id (_type_): _description_
            msg_type (_type_): _description_
            msg (dict, optional): _description_. Defaults to {}.
        """
        raw_msg = AGV.pack_msg(req_id, msg_type, msg)
        try:
            self.socket_pool.get(name).send(raw_msg)
        except Exception as e:
            logger.error('向AGV发送消息失败,可能5G网络断开,也可能是通信延迟')
            # 说明网络可能断电,所以要重新连接,所以清空原来的通讯池
            self.socket_pool = {}
            # 测试测试是否联通,如果联不通,则
            self.init_socket_pool()
    
    def receive(self, name):
        so = self.socket_pool.get(name)
        global data
        data_all = b''
        try:
            data = so.recv(16) # 接受16个字节的数据
            so.settimeout(10)
        except socket.timeout:
            logger.error('receive time out')
            so.close()
            self.socket_pool = {}
            self.init_socket_pool()
            
        if len(data) < 16: # 0-15,刚好16
            logger.error('pack head error')
            so.close()
            self.socket_pool = {}
            self.init_socket_pool()
            return 

        json_data_len = 0
        try:
            header = struct.unpack('!BBHLH6s', data)
        except Exception as e:
            logger.debug('接受字节长度出错,无法解包')
            so.close()
            self.socket_pool = {}
            self.init_socket_pool()
            return 


        json_data_len = header[3]
        data_all += data
        data = b''
        read_size = 1024

        try:
            while json_data_len > 0:
                recv = so.recv(read_size)
                data += recv
                json_data_len -= len(recv)
                if json_data_len < read_size:
                    read_size = json_data_len
            data_all += data
            return json.loads(data_all[16:].decode())
        except socket.timeout:
            so.close()
            self.socket_pool = {}
            self.init_socket_pool()
            return 

   
    @staticmethod
    def pack_msg(req_id, msg_type, msg={}):
        msg_len = 0
        json_str = json.dumps(msg)

        if msg != {}:
            msg_len = len(json_str)

        raw_msg = struct.pack('!BBHLH6s', 0x5A, 0x01, req_id,
                              msg_len, msg_type, b'\x00\x00\x00\x00\x00\x00')
        if msg != {}:
            raw_msg += bytearray(json_str, 'ascii')

        return raw_msg

    def connect(self,port,name=None):
        so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            so.connect((self.ip, port))
            so.settimeout(1)
            logger.info(f'{port} to agv ok!')
            return so
        except Exception as e:
            logger.error(f'{port} to agv fail!')
            # 关闭连接
            so.close()
            # 打印异常
            logger.error(e)
            return None


    @classmethod
    def get_agv(cls,ip,port) ->Type['AGV']:
        if cls.agv.get(ip):
            return cls.agv.get(ip)
        else:
            cls.agv[ip]=cls(ip,port)
            return cls.agv[ip]
    


if __name__=='__main__':
    AGV_IP: str = "10.13.32.11"
    AGV_PORT = {
        'status': 19204,
        'control': 19205,
        'nav': 19206,
        'config': 19207,
        'other': 19210,
        'push': 19301
    }
    tt_agv = AGV(AGV_IP,AGV_PORT)
    tt_agv.send('status',1, 1007)
    res = tt_agv.receive('status')
    map_info = tt_agv.receive('status') 
    print(map_info)



# if __name__=='__main__':
#     tt_agv = AGV.get_agv(ST.AGV_IP,ST.AGV_PORT)
#     tt_agv.send('status',1,1300)
#     map_info = tt_agv.receive('status') 
#     # print(map_info)
#     print(map_info.get('maps'))
#     # res = json.loads(map_info)
#     # print(res.get('DO'))

    
